package com.cuit.core;

import com.cuit.bean.RbCmdFactory;
import com.cuit.bean.command.RbCmd;
import com.cuit.handler.exception.DisruptorExceptionHandler;
import com.cuit.handler.risk.BaseHandler;
import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import lombok.Getter;
import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
import net.openhft.affinity.AffinityStrategies;
import net.openhft.affinity.AffinityThreadFactory;
import thirdpart.order.CmdType;
import thirdpart.order.OrderCmd;

import java.util.Timer;
import java.util.TimerTask;

import static com.cuit.handler.pub.L1PubHandler.HQ_PUB_RATE;

@Log4j2
public class EngineCore {

    private final Disruptor<RbCmd> disruptor;

    private static final int RING_BUFFER_SIZE = 1024;

    @Getter
    private final EngineApi api;

    public EngineCore(
            @NonNull final BaseHandler riskHandler,
            @NonNull final BaseHandler matchHandler,
            @NonNull final BaseHandler pubHandler
    ) {
        this.disruptor = new Disruptor<RbCmd>(
                new RbCmdFactory(),

                RING_BUFFER_SIZE,
                new AffinityThreadFactory("aft_engine_core",AffinityStrategies.ANY),

                ProducerType.SINGLE,
                new BlockingWaitStrategy()
        ) ;

        this.api = new EngineApi(disruptor.getRingBuffer());

        //1.全局异常处理器
        final DisruptorExceptionHandler<RbCmd> exceptionHandler = new DisruptorExceptionHandler<>("main",
                (ex,seq)->{
                    log.error("exception thrown on seq = {}",seq,ex);
                });
        disruptor.setDefaultExceptionHandler(exceptionHandler);

        //2.前置风控   >    撮合     >     发布数据
        disruptor.handleEventsWith(riskHandler)
                .then(matchHandler)
                .then(pubHandler);

        //3.启动
        disruptor.start();
        log.info("match engine start success");

        //4.定时任务发布行情
        new Timer().schedule(new HqPubTask(),1000,HQ_PUB_RATE);
    }

    private class HqPubTask extends TimerTask {

        @Override
        public void run() {
            api.submitCommand(OrderCmd.builder()
                    .type(CmdType.HQ_PUB)
                    .build());
        }
    }
}
